library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity  pcu is
	port (
		rseqrt, rseqz, rsltz: IN STD_LOGIC;
		instr: in std_logic_vector(31 downto 0);
		aludes: in std_logic_vector(6 downto 0);
		memdes: in std_logic_vector(6 downto 0);
		writepc, writeir, jump, branch: out std_logic;
		fwda, fwdb: out std_logic_vector(1 downto 0);
		rso, rto, rdo: buffer std_logic_vector(4 downto 0);
		controlw: out std_logic_vector(31 downto 0)
	);		
end pcu;


architecture pcu_arch of pcu is
	signal add, op_or, lw, sw, addi, ori, beq, bne, j: std_logic;
	signal regdes, Rtype: std_logic;
	signal delay: std_logic;
	signal writemem, memtoreg,writereg, aluresok, memresok: std_logic;
	signal rssource, rtsource: std_logic;	
	signal opcode, func: std_logic_vector(5 downto 0);
	signal rsi, rti, rdi: std_logic_vector(4 downto 0);
	signal aluctr: std_logic_vector(4 downto 0);
	signal alusrcb:std_logic_vector(1 downto 0);
	signal resltdes: std_logic_vector(4 downto 0);
begin
	--TODO: WRITE YOUR CODE HERE
	opcode	<=	instr(31 downto 26);
	func	<=	instr(5 downto 0);
	rsi		<=	instr(25 downto 21);
	rti 	<=	instr(20 downto 16);
	rdi 	<=	instr(15 downto 11);
	Rtype <= '1' when opcode="000000" else '0';
	add <= '1' when  Rtype&func="1100000" else '0';
	op_or <= '1' when Rtype&func="1100101" else '0';
	lw <= '1' when opcode="100011" else '0';
	sw <= '1' when opcode="101011" else '0';
	addi <= '1' when opcode="001000" else '0';
	ori <= '1' when opcode="001101" else '0';
	beq <= '1' when opcode="000100" else '0';
	bne <= '1' when opcode="000101" else '0';
	j <= '1' when opcode="000010" else '0';
	jump <= j;
	branch <= (rseqrt and beq) or (not rseqrt and bne);
	regdes <= Rtype;
	aluctr(4) <= '0';
	aluctr(3) <= op_or or ori or beq or bne;
	aluctr(2) <= '0';
	aluctr(1) <= '0';
	aluctr(0) <= add or lw or sw or addi or beq or bne;
	writemem <= sw;
	memtoreg <= lw;
	writereg <= add or op_or or addi or ori or lw;
	resltdes <= rdo when regdes='1' else rto;
	aluresok <= add or addi or op_or or ori;
	memresok <= lw; 
	alusrcb(0) <= addi or lw or sw;
	alusrcb(1) <= ori;
	
	--data hazard solution
	rssource<=add or addi or op_or or ori or beq or bne or lw or sw;
	rtsource<=add or op_or or beq or bne or sw;
	delay<='1' when aludes(6)='1' and ((rssource='1' and (rsi = aludes(4 downto 0))) or
							 (rtsource='1' and (rti = aludes(4 downto 0))))
			   else '0';
	writepc<=not delay;
	writeir<=not delay;
	rso<="00000" when delay='1' else rsi(4 downto 0);
	rto<="00000" when delay='1' else rti(4 downto 0);
	rdo<="00000" when delay='1' else rdi(4 downto 0);
	dhazard: process(rssource, rtsource, aludes, memdes, rsi, rti)
		begin
		if aludes(5)='1' and rssource='1' and (rsi = aludes(4 downto 0)) then
			fwda<="01";
		elsif (memdes(5)='1' or memdes(6)='1') and rssource='1' and
			(rsi=memdes(4 downto 0)) then
			fwda<="10";
		else
			fwda<="00";
		end if;
		if aludes(5)='1' and rtsource='1' and (rti = aludes(4 downto 0)) then
			fwdb<="01";
		elsif (memdes(5)='1' or memdes(6)='1') and rtsource='1' and (rti = memdes( 4 downto 0)) then
			fwdb<="10";
		else fwdb<="00";
		end if;
	end process;
	
	ctrlwgen: process(aluctr, writemem, memtoreg, writereg, resltdes, aluresok, memresok, alusrcb, delay)
	begin
		if (delay='0') then
			controlw(4 downto 0) 	<= aluctr;			
			controlw(7)			 	<=	writemem;
			controlw(8)			 	<=	memtoreg;
			controlw(9)			 	<= 	writereg;
			controlw(24 downto 20)	<=	resltdes(4 downto 0);
			controlw(25)			<=	aluresok;
			controlw(26)			<=	memresok;
			controlw(31 downto 30)	<=	alusrcb;
			controlw(19 downto 10)	<= "0000000000";
			controlw(29 downto 27)	<= "000";
			controlw(6 downto 5)	<= "00";
		else
			controlw(31 downto 0) 	<= x"00000000";
		end if;
	end process;
	
end pcu_arch;